<template>
  <!-- 创建游戏的主容器 -->
  <div id="main">
    <!-- 设置游戏的舞台 -->
    <div id="stage">
      <!-- 设置蛇 -->
      <div id="snake">
        <!-- snake内部的div 表示蛇的各部分 -->
        <div></div>
      </div>

      <!-- 设置食物 -->
      <div id="food">
        <!-- 添加4个小div 来设置食物的样式 -->
        <div></div>
        <div></div>
        <div></div>
        <div></div>
      </div>
    </div>
    <!-- 设置游戏的积分牌 -->
    <div id="score-panel">
      <div>
        SCORE: <span id="score">0</span>
      </div>
      <div>
        Level: <span id="level">1</span>
      </div>
    </div>
  </div>
</template>

<script lang="ts">
export default {
  mounted() {
    // 将 Food 类及其实例化移到这里
    class Food {
      element: HTMLElement;
      constructor() {
        this.element = document.getElementById('food')!;
      }
      get X() {
        return this.element.offsetLeft;
      }
      get Y() {
        return this.element.offsetTop;
      }
      change() {
        // 食物位置最小是0 最大是290 且必须是整10的倍数
        this.element.style.left = Math.round(Math.random() * 29) * 10 + 'px';
        this.element.style.top = Math.round(Math.random() * 29) * 10 + 'px';
      }
    }

    const food = new Food();
    food.change();
    console.log(food.X, food.Y);

    class ScorePanel {
      // 设置默认值为0
      score = 0;
      level = 1;

      scoreElement: HTMLElement;
      levelElement: HTMLElement;

      // 设置变量限制等级
      maxLevel: number;
      upScore: number;
      constructor(maxLevel = 10, upScore = 10) {
        this.scoreElement = document.getElementById('score')!;
        this.levelElement = document.getElementById('level')!;
        this.maxLevel = maxLevel;
        this.upScore = upScore;
      }
      //   加分
      addScore() {
        this.score += 1;
        this.scoreElement.innerText = this.score.toString();

        //   每次score等于10的倍数升级一次
        if (this.score % this.upScore === 0) {
          this.levelUp();
        }
      }
      //   升级
      levelUp() {
        this.level += 1;
        if (this.level <= this.maxLevel) {
          this.levelElement.innerText = this.level.toString();
        }
      }
    }

    const scorePanel = new ScorePanel();
    scorePanel.addScore();

    //   蛇类
    class Snake {
      // 蛇头
      head: HTMLElement;
      // 蛇身包括蛇头
      body: HTMLCollection;

      element: HTMLElement;
      constructor() {
        this.element = document.getElementById('snake')!;
        this.head = document.querySelector('#snake>div') as HTMLElement;
        this.body = document.getElementById('snake')!.getElementsByTagName('div');
      }

      //   获取蛇头坐标
      get x() {
        return this.head.offsetLeft;
      }
      get y() {
        return this.head.offsetTop;
      }
      set X(x: number) {
        if (this.x === x) {
          return;
        }
        if (x < 0 || x > 290) {
          throw new Error('超出边界');
        }
        this.moveBody();
        this.head.style.left = x + 'px';
      }
      set Y(y: number) {
        if (this.y === y) {
          return;
        }
        this.moveBody();
        this.head.style.top = y + 'px';
      }

      //   添加身体
      addBody() {
        this.element.insertAdjacentHTML('beforeend', '<div></div>');


      }
      moveBody(){
        for (let i = this.body.length - 1; i > 0; i--) {
         let X =( this.body[i - 1] as HTMLElement).offsetLeft;
         let Y =( this.body[i - 1] as HTMLElement).offsetTop;

         (this.body[i] as HTMLElement).style.left = X + 'px';
         (this.body[i] as HTMLElement).style.top = Y + 'px';
        }
      }
    }
    const snake = new Snake();

    //   游戏控制器
    class GameController {
      //   创建属性存储蛇的移动方向
      snake: Snake;
      food: Food;
      scorePanel: ScorePanel;
      direction = '';
      isLive = true;
      isMoving = false; // 新增标志位，用于判断是否正在移动
      constructor() {
        //   对Food,ScorePanel,Snake的引用
        this.snake = snake;
        this.food = food;
        this.scorePanel = scorePanel;
        this.init();
      }
      // 游戏初始化
      init() {
        //   上下左右键的监听移动蛇
        document.addEventListener('keydown', this.keydownHandler.bind(this));
      }
      //   创建键盘响应函数
      keydownHandler(event: KeyboardEvent) {
        //   修改direction的值   只有上下左右才赋值
        const newDirection = event.key;

        // 判断是否按下的是相反方向的键
        if (
            (newDirection === 'ArrowUp' && this.direction === 'ArrowDown') ||
            (newDirection === 'Up' && this.direction === 'Down') ||
            (newDirection === 'ArrowDown' && this.direction === 'ArrowUp') ||
            (newDirection === 'Down' && this.direction === 'Up') ||
            (newDirection === 'ArrowLeft' && this.direction === 'ArrowRight') ||
            (newDirection === 'Left' && this.direction === 'Right') ||
            (newDirection === 'ArrowRight' && this.direction === 'ArrowLeft') ||
            (newDirection === 'Right' && this.direction === 'Left')
        ) {
          return;
        }
        this.direction = newDirection;
        this.move(); // 新增调用move方法，立即移动一格

      }
      move() {
        /**
         * 根据方向改变蛇的位置
         */
        if (!this.isMoving) {
          this.isMoving = true;
          // 获取蛇的坐标
          let X = this.snake.x;
          let Y = this.snake.y;

          switch (this.direction) {
            case 'ArrowUp':
            case 'Up':
              // 向上移动 top 减少
              Y -= 10;
              break;
            case 'ArrowDown':
            case 'Down':
              // 向下移动 top 增加
              Y += 10;
              break;
            case 'ArrowLeft':
            case 'Left':
              // 向左移动 left 减少
              X -= 10;
              break;
            case 'ArrowRight':
            case 'Right':
              // 向右移动 left 增加
              X += 10;
              break;
          }

          this.checkFood(X, Y);
          try {
            this.snake.X = X;
            this.snake.Y = Y;
          } catch (e) {
            alert(e + ' GAME OVER!');
            this.isLive = false;
          }

          if (this.isLive) {
            setTimeout(() => {
              this.isMoving = false;
              this.move();
            }, 300 - (this.scorePanel.level - 1) * 30);
          }
        }
      }
      //   定义方法检查吃没吃到食物
      checkFood(X: number, Y: number) {
        if (X === this.food.X && Y === this.food.Y) {
          console.log('555');
          // 食物的位置要进行重置
          this.food.change();
          // 分数增加
          this.scorePanel.addScore();
          // 蛇要增加一节
          this.snake.addBody();
        }
      }
    }

    const gameController = new GameController();
  },
};
</script>

<style lang="less">
@bg-color: #b7d4a8;

// 清除默认样式
* {
  margin: 0;
  padding: 0;
  // 改变盒子模型的计算方式
  box-sizing: border-box;
}

body {
  font: bold 20px 'Courier';
}

//设置主窗口的样式
#main {
  width: 360px;
  height: 420px;
  background-color: @bg-color;
  // 设置居中
  margin: 100px auto;
  // 设置边框
  border: 10px solid black;
  // 设置圆角
  border-radius: 40px;

  // 开启弹性盒模型
  display: flex;
  // 设置主轴的方向
  flex-flow: column;
  // 设置侧轴的对齐方式
  align-items: center;
  // 设置主轴的对齐方式
  justify-content: space-around;

  // 游戏舞台
  #stage {
    width: 304px;
    height: 304px;
    border: 2px solid black;
    // 开启相对定位
    position: relative;

    // 设置蛇的样式
    #snake {
      & > div {
        width: 10px;
        height: 10px;
        background-color: #000;
        // 蛇的边框颜色和背景颜色相同
        border: 1px solid @bg-color;
        // 开启绝对定位
        position: absolute;
      }
    }

    // 设置食物
    #food {
      width: 10px;
      height: 10px;
      position: absolute;
      // 初始化一个位置
      left: 40px;
      top: 100px;

      // 开启弹性盒
      display: flex;
      // 设置横轴为主轴，wrap表示会自动换行
      flex-flow: row wrap;

      // 设置主轴和侧轴的空白空间分配到元素之间
      justify-content: space-between;
      align-content: space-between;

      & > div {
        width: 4px;
        height: 4px;
        background-color: black;

        // 使四个div旋转45度
        transform: rotate(45deg);
      }
    }
  }

  // 记分牌
  #score-panel {
    width: 300px;
    display: flex;
    // 设置主轴对齐方式
    justify-content: space-between;
  }
}
</style>
